﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Web;
using XinLife.Core.Helper;
using XinLife.Core.Model;

namespace XinLife.Controllers
{
    /// <summary>
    /// 上传下载总控制
    /// </summary>
    [AllowAnonymous]
    public class UploadController : BaseController
    {
        private readonly static object _locker = new object();

        /// <summary>
        /// 单文件上传
        /// </summary>
        /// <param name="file">文件</param>
        /// <param name="type">文件类型：avatar-头像；document-文档；image-图片；other-其它</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<AjaxResult> Upload([Required] IFormFile file, [Required, FromQuery] string type)
        {
            var uploadPath = $"webfile/{type}/{DateTime.Now:yyyyMMdd}";  // 文件上传目录
            var savePath = Path.Combine(Directory.GetCurrentDirectory(), uploadPath);  // 文件保存路径
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);
            var fileName = "";
            var rootPath = "";

            lock (_locker)
            {
                Task.Delay(50).Wait();
                fileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}_{DateTime.Now.Ticks}{Path.GetExtension(file.FileName)}";
                rootPath = $"{savePath}/{fileName}";
            }

            using var fs = new FileStream(rootPath, FileMode.Create, FileAccess.Write);
            await file.CopyToAsync(fs);
            await fs.FlushAsync();

            return Success($"{uploadPath}/{fileName}");
        }

        /// <summary>
        /// 文件下载-返回base64-不带前缀
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<AjaxResult> Download(string filePath)
        {
            return await Task.Factory.StartNew(() =>
            {
                var baseDirec = Directory.GetCurrentDirectory();
                var rootPath = Path.Combine(baseDirec, filePath).Replace("\\", "/");
                if (!System.IO.File.Exists(rootPath))
                {
                    return Error("未找到文件");
                }else
                {
                    string path = Path.Combine(baseDirec, "webfile");
                    FileInfo fileInfo = new FileInfo(rootPath);
                    if (!fileInfo.FullName.Contains(path))
                    {
                        return Error("非法路径!");
                    }
                }

                var bts = System.IO.File.ReadAllBytes(rootPath);
                var str = Convert.ToBase64String(bts);

                return Success(str);
            });
        }

        /// <summary>
        /// 下载
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult> Down(string filePath)
        {
            var baseDirec = Directory.GetCurrentDirectory();
            var rootPath = Path.Combine(baseDirec, filePath).Replace("\\", "/");
            if (System.IO.File.Exists(rootPath))
            {
                string path = Path.Combine(baseDirec, "webfile");
                FileInfo fileInfo = new FileInfo(rootPath);
                if (!fileInfo.FullName.Contains(path))
                {
                    return BadRequest("非法路径!");
                }

                var bts = await System.IO.File.ReadAllBytesAsync(rootPath);
                var fileName = Path.GetFileName(filePath);
                if (fileName.IndexOf("__++__") != -1)
                {
                    fileName = fileName.Split("__++__")[0] + Path.GetExtension(filePath);
                }

                return File(bts, "image/png", fileName);
            }
            return BadRequest("未找到文件");
        }

        /// <summary>
        /// 多文件下载-返回一个压缩包路劲
        /// </summary>
        /// <param name="filePaths"></param>
        /// <returns></returns>
        [HttpPost]
        public AjaxResult Down(List<string> filePaths)
        {
            var baseDirec = Directory.GetCurrentDirectory();
            var zipDirec = "webfile/temp/zipArchive";
            var zipName = $"{DateTime.Now:yyyyMMddHHmmss}.zip";
            var zipSavePath = Path.Combine(baseDirec, zipDirec).Replace("\\", "/");
            if (!Directory.Exists(zipSavePath)) Directory.CreateDirectory(zipSavePath);
            ZipHelper.FilesZip(filePaths, Path.Combine(zipSavePath, zipName));

            return Success(zipDirec + "/" + zipName);
        }

        ///  <summary>
        /// 大文件下载
        /// a标签，或者 window.open
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns></returns>
        [HttpGet, AllowAnonymous]
        public async Task<IActionResult> DownBigFile(string filePath)
        {
            var root = Directory.GetCurrentDirectory();
            filePath = Path.Combine(root, filePath);
            if (!System.IO.File.Exists(filePath)) return BadRequest("未找到文件");
            var fileName = filePath[(filePath.LastIndexOf("/") + 1)..];
            var downSize = 1024 * 4; // 每次下载大小
            Response.ContentType = "application/octet-stream";
            Response.Headers.Add("Content-Disposition", $"attachment; filename={HttpUtility.UrlEncode(fileName)}");
            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer;
                var fsLength = fs.Length;  // 文件大小，每次读取后减去本次读取的字节，用于计算剩余大小
                while (fsLength > 0)
                {
                    if (HttpContext.RequestAborted.IsCancellationRequested) break;
                    if (fsLength >= downSize)
                        buffer = new byte[downSize];
                    else
                        buffer = new byte[fsLength];
                    int curRead = await fs.ReadAsync(buffer, 0, buffer.Length);// 本次读取的大小
                    await Response.Body.WriteAsync(buffer, 0, curRead);
                    await Response.Body.FlushAsync();
                    fsLength -= curRead;
                }
            }
            return new EmptyResult();
        }

    }
}
